﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Text;

namespace Ycg.Logging
{
    public static class StackFrameWrapper
    {
        public static string GetStackTraceContent()
        {
            int startLocation = 2;
            StackTrace stackTrace = new StackTrace();
            StringBuilder stringBuilder = new StringBuilder(300);
            for (int number = startLocation; number < stackTrace.FrameCount; number++)
            {
                StackFrame stackFrame = new StackFrame(number);
                MethodBase methodInfo = stackFrame.GetMethod();

                GetMethodTrace(methodInfo, stringBuilder);
                GetGenericTrace(methodInfo, stringBuilder);
                GetParameterTrace(methodInfo, stringBuilder);
                GetFilePathAndLineTrace(stackFrame, stringBuilder);

                if (number != stackTrace.FrameCount - 1)
                {
                    stringBuilder.Append(Environment.NewLine);
                }
            }

            return stringBuilder.ToString();
        }

        private static void GetMethodTrace(MethodBase methodInfo, StringBuilder stringBuilder)
        {
            if (methodInfo.DeclaringType != null)
            {
                stringBuilder.Append(methodInfo.DeclaringType.FullName);
            }
            stringBuilder.Append(".");
            stringBuilder.Append(methodInfo.Name);
        }

        private static void GetGenericTrace(MethodBase methodInfo, StringBuilder stringBuilder)
        {
            if ((methodInfo is MethodInfo) && methodInfo.IsGenericMethod)
            {
                Type[] genericArguments = methodInfo.GetGenericArguments();
                stringBuilder.Append("[");
                bool flag = true;
                foreach (Type argument in genericArguments)
                {
                    if (flag)
                    {
                        flag = false;
                    }
                    else
                    {
                        stringBuilder.Append(",");
                    }
                    stringBuilder.Append(argument.Name);
                }
                stringBuilder.Append("]");
            }
        }

        private static void GetParameterTrace(MethodBase methodInfo, StringBuilder stringBuilder)
        {
            ParameterInfo[] parameterInfos = methodInfo.GetParameters();
            if (parameterInfos.Length > 0)
            {
                stringBuilder.Append("(");
                bool parameterFlag = true;
                foreach (ParameterInfo parameterInfo in parameterInfos)
                {
                    if (parameterFlag)
                    {
                        parameterFlag = false;
                    }
                    else
                    {
                        stringBuilder.Append(",");
                    }
                    stringBuilder.Append(parameterInfo.ParameterType.Name);
                    stringBuilder.Append(" ");
                    stringBuilder.Append(parameterInfo.Name);
                }
                stringBuilder.Append(")");
            }
        }

        private static void GetFilePathAndLineTrace(StackFrame stackFrame, StringBuilder stringBuilder)
        {
            string format = "in {0} : line {1}";
            if (stackFrame.GetILOffset() != -1)
            {
                string fileName = stackFrame.GetFileName();
                if (fileName != null)
                {
                    stringBuilder.Append(" ");
                    stringBuilder.AppendFormat(CultureInfo.InvariantCulture, format, new object[] { fileName, stackFrame.GetFileLineNumber() });
                }
            }
        }
    }
}
